package cn.schoolwow.workflow.module.task.job.service;

import cn.schoolwow.data.thread.QuickDataThread;
import cn.schoolwow.data.thread.QuickDataThreadBuilder;
import cn.schoolwow.data.thread.domain.execute.type.single.SingleDataThreadHandler;
import cn.schoolwow.quickdao.domain.DAO;
import cn.schoolwow.quickdao.domain.database.dql.condition.Condition;
import cn.schoolwow.quickdao.domain.database.dql.subCondition.SubCondition;
import cn.schoolwow.quickdao.domain.transaction.Transaction;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.workflow.domain.task.WorkFlowTaskResponse;
import cn.schoolwow.workflow.entity.WorkFlowInstance;
import cn.schoolwow.workflow.entity.WorkFlowInstanceHistory;
import cn.schoolwow.workflow.entity.WorkFlowNode;
import cn.schoolwow.workflow.entity.WorkFlowTask;
import cn.schoolwow.workflow.module.common.domain.QuickWorkFlowOption;
import cn.schoolwow.workflow.module.common.flow.AddWorkFlowHistoryFlow;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

public class CheckTaskTimeoutServiceFlow implements BusinessFlow {
    private static QuickDataThread quickDataThread;
    static{
        quickDataThread = QuickDataThreadBuilder.newInstance().build();
    }

    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        checkRequest(flowContext);
        setCondition(flowContext);
        setWorkFlowNodeSubCondition(flowContext);
        setWorkFlowInstanceSubCondition(flowContext);
        executeCondition(flowContext);
    }

    @Override
    public String name() {
        return "监听工作流任务是否超期服务流程";
    }

    private void checkRequest(FlowContext flowContext){
        QuickWorkFlowOption quickWorkFlowOption = flowContext.checkInstanceData(QuickWorkFlowOption.class);

        if(null==quickWorkFlowOption.workFlowTaskListener){
            flowContext.brokenCurrentFlow("用户未配置工作流任务监听器!跳过工作流超期任务检查");
        }
    }

    private void setCondition(FlowContext flowContext){
        DAO dao = flowContext.checkInstanceData(DAO.class);

        Condition condition = dao.query(WorkFlowTask.class)
                .addQuery("complete", false)
                .addColumnAs("id", "taskId")
                .addColumnAs("taskName", "taskName")
                .addColumnAs("complete","complete")
                .addColumnAs("createdAt", "taskCreatedTime");
        flowContext.putCurrentFlowInstanceData(condition, Condition.class);
    }

    private void setWorkFlowNodeSubCondition(FlowContext flowContext){
        Condition condition = flowContext.checkInstanceData(Condition.class);

        SubCondition workFlowNodeSubCondition = condition.joinTable(WorkFlowNode.class,"nodeId","id")
                .addQuery("timeout", ">",0)
                .addColumnAs("timeout","timeout");
        flowContext.putCurrentFlowData("workFlowNodeSubCondition", workFlowNodeSubCondition);
    }

    private void setWorkFlowInstanceSubCondition(FlowContext flowContext){
        Condition condition = flowContext.checkInstanceData(Condition.class);

        SubCondition workFlowInstanceSubCondition = condition.joinTable(WorkFlowInstance.class,"instanceId","id")
                .addQuery("status", 0)
                .addColumn("definitionId")
                .addColumnAs("id","instanceId")
                .addColumnAs("name","instanceName")
                .addColumnAs("status","instanceStatus")
                .addColumnAs("initiator","initiator")
                .addColumnAs("contextData","contextData")
                .addColumnAs("createdAt","instanceCreatedTime");
        flowContext.putCurrentFlowData("workFlowInstanceSubCondition", workFlowInstanceSubCondition);
    }

    private void executeCondition(FlowContext flowContext){
        Condition condition = flowContext.checkInstanceData(Condition.class);
        QuickWorkFlowOption quickWorkFlowOption = flowContext.checkInstanceData(QuickWorkFlowOption.class);
        DAO dao = flowContext.checkInstanceData(DAO.class);

        List<WorkFlowTaskResponse> workFlowTaskResponseList = condition.execute().getList(WorkFlowTaskResponse.class);
        if(null==workFlowTaskResponseList||workFlowTaskResponseList.isEmpty()){
            return;
        }
        quickDataThread.singleDataThreadWork(WorkFlowTaskResponse.class)
                .list(workFlowTaskResponseList)
                .singleDataThreadHandler(new SingleDataThreadHandler<WorkFlowTaskResponse>() {
                    @Override
                    public void handleSingleList(WorkFlowTaskResponse workFlowTaskResponse) throws Exception {
                        //判断是否超时
                        if(workFlowTaskResponse.taskCreatedTime.plusSeconds(workFlowTaskResponse.timeout).isAfter(LocalDateTime.now())){
                            return;
                        }
                        //判断当天是否已经发送过提醒
                        long count = dao.query(WorkFlowInstanceHistory.class)
                                .addQuery("workFlowInstanceId", workFlowTaskResponse.instanceId)
                                .addQuery("message","审批任务["+workFlowTaskResponse.taskName+"]超时处理")
                                .addQuery("DATE_FORMAT(created_at, '%Y-%m-%d')", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                                .execute()
                                .count();
                        if(count>0){
                            return;
                        }
                        dao.startTransaction(transaction -> {
                            flowContext.startFlow(new AddWorkFlowHistoryFlow())
                                    .putCurrentCompositeFlowData("workFlowInstanceId", workFlowTaskResponse.instanceId)
                                    .putCurrentCompositeFlowData("message", "审批任务["+workFlowTaskResponse.taskName+"]超时处理")
                                    .putCurrentCompositeFlowData("assigner", "系统")
                                    .putCurrentFlowInstanceData(transaction, Transaction.class)
                                    .execute();
                            quickWorkFlowOption.workFlowTaskListener.afterTaskTimeout(workFlowTaskResponse);
                        });
                    }
                })
                .execute();
    }
}
